import React from 'react';
import PropTypes from 'prop-types';
import cn from 'classnames';

import * as echarts from 'echarts';
import dayjs from 'dayjs';
import ECharts from '@kuiper-components/echarts';

import { datetime, number } from '../../../../../common/formatter';
import { WARNING_CATEGORY_KEY_LABEL_MAP } from '../../../../../common/constants';

import RadioButton, {
	Group as RadioGroup,
} from '../../../../components/RadioButton';
import Helper from '../../../../components/Helper';
import Box from '../Box';
import s from './Trend.module.css';


const numFormat = number;

export default function Trend({ className, dateRask = {}, stats }) {
	const taskQuickMark = dateRask.detectTime;
	const [type, setType] = React.useState('_ALL_');
	const [myChart, setChart] = React.useState(undefined);
	const emptyLineData = []

	for (let i = 7; i >= 1; i--) {
		emptyLineData.push([
			dayjs().subtract(i, 'days').startOf('day').toDate(),
			0,
			0,
			0,
			0,
		]);
	}

  // 渲染数据到图表
  const trendDataFormatter = ([{ data }]) => {
  const endTime = data[0]

  const allDataRender = ([
    endTime,        // 结束时间
    warningUrlCount,// 风险URL总数
    lowLevelCount,  // 高危URL
    highLevelCount, // 低危URL
  ]) => `
   <tr>
       <td style="padding: 0.25rem 0.5rem;">风险URL总数</td>
       <td style="text-align: right; padding: 0.5em;">${numFormat(warningUrlCount)}个</td>
     </tr>
     <tr>
       <td style="padding: 0.25rem 0.5rem;">高危</td>
       <td style="text-align: right; padding: 0.5em;">${numFormat(highLevelCount)}个</td>
     </tr>
     <tr>
       <td style="padding: 0.25rem 0.5rem;">低危</td>
       <td style="text-align: right; padding: 0.5em;">${numFormat(lowLevelCount)}个</td>
   </tr>
`
  const keywordRender = ([
    endTime,        // 结束时间
    keyWordsCount,  // 敏感词命中数
  ]) => `
   <tr>
      <td style="padding: 0.25rem 0.5rem;">敏感词总数</td>
      <td style="text-align: right; padding: 0.5em;">${numFormat(keyWordsCount)}个</td>
   </tr>
`
  const changeTypeRender = ([
    endTime,             // 结束时间
    allChangeCount,      // 变更数
    textChangeCount,     // 文本变更
    structureChangeCount,// 结构变更
    resourceChangeCount  // 资源变更
  ]) => `
       <tr>
           <td style="padding: 0.25rem 0.5rem;">变更信息</td>
           <td style="text-align: right; padding: 0.5em;">${numFormat(allChangeCount)}个</td>
         </tr>
         <tr>
           <td style="padding: 0.25rem 0.5rem;">文本变更</td>
           <td style="text-align: right; padding: 0.5em;">${numFormat(textChangeCount)}个</td>
         </tr>
         <tr>
           <td style="padding: 0.25rem 0.5rem;">结构变更</td>
           <td style="text-align: right; padding: 0.5em;">${numFormat(structureChangeCount)}个</td>
         </tr>
         <tr>
           <td style="padding: 0.25rem 0.5rem;">资源变更</td>
           <td style="text-align: right; padding: 0.5em;">${numFormat(resourceChangeCount)}个</td>
         </tr>
   `
  return `
    <div>
      <div style="width: 100%; text-align: left; border-bottom: 1px solid var(--color-border-2); padding: 0.5rem 0.75rem; margin-bottom: 0.25rem;">
        ${datetime(endTime)}
      </div>
      <table style="width: 100%;">
        <tbody>
         ${type === "_ALL_" && allDataRender(data) || ''}
         ${type === "changeType" && changeTypeRender(data) || ''}
         ${type === "keyword" && keywordRender(data) || ''}
        </tbody>
      </table>
    </div>
  `;
  }

	const option = {
		tooltip: {
			trigger: 'axis',
			axisPointer: {
				type: 'cross',
			},
			formatter:trendDataFormatter,
			backgroundColor: '#fff',
			textStyle: '#696C78',
			extraCssText:
				'min-width: 10rem; color: var(--color-text-1); line-height: 1rem; margin: 0 auto; box-shadow: 0 0 3px rgba(0, 0, 0, 0.3);',
		},
		axisPointer: {
			show: true,
			lineStyle: {
				width: 2,
				type: 'dotted',
				color: '#F0443C',
			},
		},
		grid: {
			left: '48',
			right: '110',
			top: '24',
			bottom: '48',
		},
		xAxis: {
			type: 'time',
			boundaryGap: false,
			splitNumber: 7,
			splitLine: { show: false },
			axisLine: { lineStyle: { color: 'transparent' }, show: false },
			axisTick: {
				show: false,
			},
			axisLabel: {
				showMaxLabel: false,
				formatter(value) {
					const date = new Date(value);
					return datetime(date, 'YYYY-MM-DD HH:mm:ss');
				},
				margin: 20,
				align: 'left',
			},
		},
		yAxis: {
			type: 'value',
			boundaryGap: false,
			axisTick: {
				show: false,
			},
			splitLine: { lineStyle: { color: '#F7F9FC' }, show: true },
			axisLine: { lineStyle: { color: 'transparent' }, show: false },
		},
		textStyle: { color: '#696C78', fontSize: 12 },
		series: [
			{
				data: emptyLineData,
				name: '全部',
				type: 'line',
				smooth: true,
				smoothMonotone: 'x',
				showSymbol: false,
				lineStyle: {
					color: '#FAAF2C',
					width: 2,
				},
				areaStyle: {
					color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
						{
							offset: 0,
							color: 'rgba(255, 165, 78, 0.4977)',
						},
						{
							offset: 1,
							color: 'rgba(249, 222, 105, 0.0001)',
						},
					]),
				},
			},
		],
	};

  // 计算三种变更文本(text structure resource)中命中的铭感词
  const calculateKeyWordsCount = (stat)=>{
   return stat?.result?.warnings?.reduce((count,warning)=>{
          const textChangeHitWords = warning?.detail?.text?.words?.length || 0
          const structureChangeHitWords = warning?.detail?.text?.structure?.length || 0
          const resourceChangeHitWords = warning?.detail?.text?.resource?.length || 0

          return count
          +textChangeHitWords
          +structureChangeHitWords
          +resourceChangeHitWords
    },0)
  }
  // 计算不同等级的url数量
  const calculateUrlCount = (stat, level)=>{
    let levelRank = 0
    if(level==="low"){ levelRank = 2 }
    if(level==="high"){ levelRank = 4 }

    return stat?.result?.warnings?.reduce((count,warning)=>{
     return warning.level===levelRank
     ?++count
     :count
    },0)
    ||0
  }
  // 计算三种类型变更数量
  const calculateChangeCount = (stat)=>{
    const textChangeCount = stat?.result?.warnings?.reduce((count,warning)=>warning?.detail?.text ?++count:count,0)
    const structureChangeCount = stat?.result?.warnings?.reduce((count,warning)=>warning?.detail?.structure ?++count:count,0)
    const resourceChangeCount = stat?.result?.warnings?.reduce((count,warning)=>warning?.detail?.resource ?++count:count,0)
    const allChangeCount = (textChangeCount+structureChangeCount+resourceChangeCount) || 0

    return {
      allChangeCount,
      textChangeCount,
      structureChangeCount,
      resourceChangeCount
    }
  }

  // 格式化"全部" 节点数据
  const formatAllDataNodes = (stats)=>{
    option.series[0].data = stats.map(item=>{
      const endTime = item.endTime
      const warningUrlCount = item.result.warningCount
      const lowLevelCount = calculateUrlCount(item,'low')
      const highLevelCount = calculateUrlCount(item,'high')
      const keyWordsCount = calculateKeyWordsCount(item)
      return [
        endTime,        // 结束时间
        warningUrlCount,// 风险URL总数
        lowLevelCount,  // 高危URL
        highLevelCount, // 低危URL
        keyWordsCount,  // 敏感词命中数
      ]
    })


  }
  // 格式化"变更类型" 节点数据
  const formatChangeTypeNodes = (stats)=>{
    option.series[0].data = stats.map(item=>{
      const endTime = item.endTime
      const {
        allChangeCount,
        textChangeCount,
        structureChangeCount,
        resourceChangeCount
      } = calculateChangeCount(item)

      return [
        endTime,             // 结束时间
        allChangeCount,      // 变更数
        textChangeCount,     // 文本变更
        structureChangeCount,// 结构变更
        resourceChangeCount  // 资源变更
      ]
    })
  }
  // 格式化"敏感词" 节点数据
  const formatKeywordNodes = (stats)=>{
    option.series[0].data = stats.map(item=>{
      const endTime = item.endTime
      const keyWordsCount = calculateKeyWordsCount(item)
      return [
        endTime,        // 结束时间
        keyWordsCount,  // 敏感词命中数
      ]
    })
  }

  // 时间排序
  const sortAllNodeByTime = ()=>{
    option.series[0].data.sort(
			(a, b) => new Date(a[0]).getTime() - new Date(b[0]).getTime()
		);
  }
  // 填充无数据的节点
  const fillEmptyNodeData = ()=>{
    while (option.series[0].data.length < 10) {
      const newEmptyNode = [
        dayjs(option.series[0].data[0][0]).subtract(1, 'days').toDate().getTime(),
        0,0,0,0
      ]
			option.series[0].data.unshift(newEmptyNode);
		}
  }
  // 计算Y轴最大值
  const calculateMaxYAxis = ()=>{
    return option.series[0].data.reduce((max, b) => {
			if (b[1] > max) return b[1];
			return max;
		}, 10+3);
  }

  // 生成表格所需数据
	if (stats?.length) {
    if(type==="_ALL_"){formatAllDataNodes(stats)}
    else if(type==="changeType"){formatChangeTypeNodes(stats)}
    else if(type==="keyword"){formatKeywordNodes(stats)}

    sortAllNodeByTime()

    fillEmptyNodeData()

		option.yAxis.max = calculateMaxYAxis();

	} else {
		option.series[0].data = JSON.parse(JSON.stringify(emptyLineData))
		option.tooltip.show = false
		option.axisPointer.show = false
		option.series[0].lineStyle.width = 0
		option.yAxis.splitNumber = 5
		option.yAxis.max = 5
		option.yAxis.min = 0
	}

	if (taskQuickMark !== 'range') {
		const data = option.series[0].data;
		let highLightIdx = -1;
		let coordItem;
		if (taskQuickMark === 'last') {
			coordItem = data[data.length - 1];
			highLightIdx = stats.length - 1
		} else {
			coordItem = data[data.length - 2];
			highLightIdx = stats.length - 2
		}
		const coord = [coordItem[0], coordItem[1]];

		if (highLightIdx > -1) {
			option.series[0].markPoint = {
				label: {
					formatter: `${taskQuickMark === 'last' ? '最新一次监测' : '上次监测'}`,
					position: 'top',
				},
				data: [{ coord }],
				symbolSize: 24,
				itemStyle: {
					color: '#F1443C',
				},
			};
		} else {
			option.series[0].markPoint = {};
		}
	}
	const getChart = e => {
		setChart(e);
	};
	if (myChart) {
		myChart.clear()
		myChart.setOption(option);
	}
	return (
		<Box
			title={
				<>
					发现篡改事件趋势
					<Helper overlay="按风险URL统计" placement="top" />
				</>
			}
			headerLeft={
				<RadioGroup className={s.levelSelect} value={type} onChange={setType}>
					<RadioButton borderless key="_ALL_" className={s.radio}>
						全部
					</RadioButton>
					{Object.entries(WARNING_CATEGORY_KEY_LABEL_MAP.checkChange).map(
						([key, label]) => (
							<RadioButton borderless key={key} className={s.radio}>
								{label}
							</RadioButton>
						)
					)}
				</RadioGroup>
			}
			className={cn(className, s.trend)}
		>
			<ECharts
				className={s.chart}
				option={option}
				getInstance={getChart}
			/>
		</Box>
	);
}

Trend.propTypes = {
	className: PropTypes.string,
	stats: PropTypes.arrayOf(
		PropTypes.shape({
			target: PropTypes.string,
			name: PropTypes.string,
			endTime: PropTypes.string,
		})
	),
	jobId: PropTypes.string,
	dateRask: PropTypes.object,
};

Trend.defaultProps = {
	className: s.vulTrend,
};
